package com.seanchenxi.gwt.xmlrpc.client;

import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.seanchenxi.gwt.xmlrpc.client.impl.BaseResponseHandler;
import com.seanchenxi.gwt.xmlrpc.client.impl.XmlRpcClientConfigImpl;
import com.seanchenxi.gwt.xmlrpc.client.util.XmlRpcParser;

/**
 * The Class XmlRpcClient.
 */
public class XmlRpcClient extends AbstractXmlRpcClient {
	
	/**
	 * Instantiates a new xml rpc client.
	 * 
	 * @param url
	 *            the xml rpc url
	 */
	public XmlRpcClient(String url) {
		super(url);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.seanchenxi.gwt.xmlrpc.client.AbstractXmlRpcClient#send(com.seanchenxi
	 * .gwt.xmlrpc.client.XmlRpcRequest,
	 * com.google.gwt.user.client.rpc.AsyncCallback)
	 */
	@Override
	public <T> void send(XmlRpcRequest<T> xmlRpcRequest,
			AsyncCallback<T> callback) {
		send(xmlRpcRequest, callback, new BaseResponseHandler<T>());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.seanchenxi.gwt.xmlrpc.client.AbstractXmlRpcClient#send(com.seanchenxi
	 * .gwt.xmlrpc.client.XmlRpcRequest,
	 * com.google.gwt.user.client.rpc.AsyncCallback,
	 * com.seanchenxi.gwt.xmlrpc.client.ResponseHandler)
	 */
	@Override
	public <T> void send(XmlRpcRequest<T> xmlRpcRequest,
			final AsyncCallback<T> callback,
			final ResponseHandler<? extends T> handler) {

		RequestCallback requestCallBack = new RequestCallback() {

			@Override
			public void onResponseReceived(Request request, Response response) {
				if (200 == response.getStatusCode()) {
					callback.onSuccess(handler.handleResponse(response.getText()));
				} else if (Response.SC_UNAUTHORIZED == response.getStatusCode()) {
		            String message = "Need to log in";
		            callback.onFailure(new XmlRpcException(Response.SC_UNAUTHORIZED, message));
		        } else if (response.getStatusCode() > 0) {
		            String message = "Server Error " + response.getStatusCode()
		                + " " + response.getStatusText() +" " + response.getText();
		            callback.onFailure(new XmlRpcException(response.getStatusCode(), message));
		        }
			}

			@Override
			public void onError(Request request, Throwable exception) {
				callback.onFailure(exception);
			}
		};

		try {
			send(xmlRpcRequest, requestCallBack);
		} catch (RequestException e) {
			callback.onFailure(e);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.seanchenxi.gwt.xmlrpc.client.AbstractXmlRpcClient#send(com.seanchenxi
	 * .gwt.xmlrpc.client.XmlRpcRequest,
	 * com.google.gwt.http.client.RequestCallback)
	 */
	@Override
	protected <T> void send(XmlRpcRequest<T> xmlRpcRequest,
			RequestCallback requestCallBack) throws RequestException {

		send(XmlRpcParser.writeRequestData(xmlRpcRequest), requestCallBack);

	}

	/**
	 * Send.
	 * 
	 * @param requestData
	 *            the request data
	 * @param requestCallBack
	 *            the request call back
	 * @throws RequestException
	 *             the request exception
	 */
	private void send(String requestData, RequestCallback requestCallBack)
			throws RequestException {

		RequestBuilder builder = createBuilder();

		builder.setRequestData(requestData);

		builder.setCallback(requestCallBack);

		builder.send();
	}

	/**
	 * Creates the xml rpc request.
	 * 
	 * @param <T>
	 *            the generic type
	 * @param methodName
	 *            the method name
	 * @param params
	 *            the params
	 * @return the xml rpc request
	 */
	protected <T> XmlRpcRequest<T> createRequest(String methodName,
			Object... params) {
		return XmlRpcObjectFactory.createRequest(methodName, params);
	}

	/**
	 * Creates a new RequestBuilder object.
	 * 
	 * @return the request builder
	 */
	protected RequestBuilder createBuilder() {

		RequestBuilder builder = null;

		assert (getConfig() != null);

		builder = new RequestBuilder(RequestBuilder.POST, getConfig().getUrl());
		builder.setHeader("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
		builder.setHeader("Content-Encoding","gzip");
		builder.setHeader("Content-Type", "text/xml; charset=utf-8");
		builder.setHeader("Pragma", "no-cache");
		builder.setHeader("Transfer-Encoding","chunked");
		builder.setHeader("X-XSS-Protection","1; mode=block");
		
		if (getConfig().getUsername() != null)
			builder.setUser(getConfig().getUsername());

		if (getConfig().getPassword() != null)
			builder.setPassword(getConfig().getPassword());

		builder.setTimeoutMillis(getConfig().getTimeout());

		assert (builder != null);

		return builder;
	}

	/**
	 * Sets the auth.
	 * 
	 * @param userName
	 *            the user name
	 * @param password
	 *            the password
	 * @return true, if successful
	 */
	public boolean setAuth(String userName, String password) {
		if (getConfig() == null)
			return false;
		if (userName == null || password == null)
			return false;
		if (userName.length() < 1 || password.length() < 1)
			return false;
		((XmlRpcClientConfigImpl) getConfig()).setUsername(userName);
		((XmlRpcClientConfigImpl) getConfig()).setPassword(password);
		return true;
	}

	/**
	 * Sets the time out.
	 * 
	 * @param timeout
	 *            the timeout
	 * @return true, if successful
	 */
	public boolean setTimeOut(int timeout) {
		if (getConfig() == null)
			return false;

		if (timeout < 1000)
			return false;
		((XmlRpcClientConfigImpl) getConfig()).setTimeout(timeout);
		return true;
	}
}
